package cn.ibdsr.human.service.impl;

import cn.ibdsr.human.constant.*;
import cn.ibdsr.human.db.mapper.CompanyMapper;
import cn.ibdsr.human.db.mapper.LoginLogMapper;
import cn.ibdsr.human.db.mapper.PlatformUserMapper;
import cn.ibdsr.human.db.mapper.UserMapper;
import cn.ibdsr.human.db.model.*;
import cn.ibdsr.human.exception.BizExceptionEnum;
import cn.ibdsr.human.service.CompanyService;
import cn.ibdsr.human.service.UserDetailService;
import cn.ibdsr.human.service.UserService;
import cn.ibdsr.human.transfer.*;
import cn.ibdsr.human.transfer.platform.PlatformUserDetialDTO;
import cn.ibdsr.human.transfer.platform.ResetPasswordDTO;
import cn.ibdsr.human.util.*;
import cn.ibdsr.human.exception.BusinessException;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * @author chenglx
 * @version V1.0
 * @description
 * @createDate 2020-02-28 15:19
 * <p>
 * Date Author Description
 * ------------------------------------------------------
 * 2020-02-28 chenglx init
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    private final static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private CompanyMapper companyMapper;
    @Resource
    private CompanyService companyService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private PlatformUserMapper platformUserMapper;

    @Resource
    private LoginLogMapper loginLogMapper;
    @Resource
    private UserDetailService userDetailService;
    /**
     * 检查平台账号
     *
     * @param account 账号
     * @return
     */
    private PlatformUser checkPlatAccount(String account) {
        QueryWrapper<PlatformUser> platformUserQueryWrapper=new QueryWrapper<>();
        platformUserQueryWrapper.eq("account", account);
        platformUserQueryWrapper.eq("is_deleted", IsDeleted.NORMAL.getCode());
        PlatformUser platformUser = platformUserMapper.selectOne(platformUserQueryWrapper);
        return platformUser;
    }
    /**
     * 根据售票员账号获取账号信息
     *
     * @param account 账号
     * @return
     */
    private User checkUserAccount(String account,Integer sysType) {
        QueryWrapper<User> userQueryWrapper=new QueryWrapper<>();
        userQueryWrapper.eq("account", account);
        userQueryWrapper.eq("sys_type", sysType);
        userQueryWrapper.eq("is_deleted", IsDeleted.NORMAL.getCode());
        User user = userMapper.selectOne(userQueryWrapper);
        return user;
    }
    @Transactional
    @Override
    public UserLoginResponse loginOperate(UserLoginDTO userLoginDTO) {
        String account=userLoginDTO.getAccount();
        String password=userLoginDTO.getPassword();
        Integer sysType=userLoginDTO.getSysType();
        Long userId=null;
        String userName=null;
        if(sysType== PlatformEnum.PLATFORM.getCode()){
            PlatformUser platformUser = checkPlatAccount(account);
            if(platformUser==null){
                throw new BusinessException(BizExceptionEnum.ACCOUNT_NOT_EXIST);
            }
            if(platformUser.getStatus().equals(UserStatusEnum.FROZEN.getType())){
                throw new BusinessException(BizExceptionEnum.ACCOUNT_DISABLE);
            }
            String inputPassword = ShiroKit.md5(password, platformUser.getSalt());
            if (!inputPassword.equals(platformUser.getPassword())) {
                throw new BusinessException(BizExceptionEnum.PASSWORD_ERROR);
            }
            platformUser.setUpdateTime(LocalDateTime.now());
            platformUser.updateById();
            userId=platformUser.getId();
            userName=platformUser.getName();
        }else {
            User user = checkUserAccount(account,sysType);
            if(user==null){
                throw new BusinessException(BizExceptionEnum.ACCOUNT_NOT_EXIST);
            }
            if(user.getStatus().equals(UserStatusEnum.FROZEN.getType())){
                throw new BusinessException(BizExceptionEnum.ACCOUNT_DISABLE);
            }

            String inputPassword = ShiroKit.md5(password, user.getSalt());
            if (!inputPassword.equals(user.getPassword())) {
                throw new BusinessException(BizExceptionEnum.PASSWORD_ERROR);
            }
            user.setUpdateTime(LocalDateTime.now());
            user.updateById();
            userId=user.getId();
            userName=user.getName();
        }

        //token-areaid登录接口
        String userAccount = account;
        String token = JwtTokenUtil.generateToken(sysType+":"+userId + ":" + userAccount);


        String ip = IPUtils.getIPAddress(HttpServletUtils.getRequest());

        token=addLoginRedis(sysType,account,token);

        UserLoginResponse userLoginResponse=new UserLoginResponse();
        userLoginResponse.setName(userName);
        userLoginResponse.setToken(token);

        LoginLog loginLog=new LoginLog();
        loginLog.setLoginUserId(userId);
        loginLog.setSysType(sysType);
        loginLog.setIp(ip);
        loginLog.setCreateTime(LocalDateTime.now());
        loginLogMapper.insert(loginLog);
        return userLoginResponse;
    }

    @Override
    public void changePwd(PasswordDTO passwordDTO, Long userId) {


        if (passwordDTO.getOldPwd().equals(passwordDTO.getNewPwd())) {
            throw new BusinessException(BizExceptionEnum.OLD_NEW_PWD_IS_SAME);
        }

        if (!passwordDTO.getRePwd().equals(passwordDTO.getNewPwd())) {
            throw new BusinessException(BizExceptionEnum.TWO_PWD_NOT_MATCH);
        }

        Integer sysType=passwordDTO.getSysType();

        if(!sysType.equals(PlatformEnum.PLATFORM.getCode())){
            User user = userMapper.selectById(userId);
            if (user == null) {
                throw new BusinessException(BizExceptionEnum.ACCOUNT_NOT_EXIST);
            }
            if (user.getStatus().equals(UserStatusEnum.FROZEN.getType())) {
                throw new BusinessException(BizExceptionEnum.ACCOUNT_DISABLE);
            }

            String inputPassword = ShiroKit.md5(passwordDTO.getOldPwd(), user.getSalt());
            if (!inputPassword.equals(user.getPassword())) {
                throw new BusinessException(BizExceptionEnum.OLD_PWD_NOT_RIGHT);
            }

            if (!passwordDTO.getNewPwd().equals(passwordDTO.getRePwd())) {
                throw new BusinessException(BizExceptionEnum.TWO_PWD_NOT_MATCH);
            }
            user.setPassword(ShiroKit.md5(passwordDTO.getNewPwd(), user.getSalt()));
            user.setUpdateTime(LocalDateTime.now());
            user.updateById();
            deleteLoginRedis(sysType,user.getAccount());
        }else {
            PlatformUser user = platformUserMapper.selectById(userId);
            if (user == null) {
                throw new BusinessException(BizExceptionEnum.ACCOUNT_NOT_EXIST);
            }
            if (user.getStatus().equals(UserStatusEnum.FROZEN.getType())) {
                throw new BusinessException(BizExceptionEnum.ACCOUNT_DISABLE);
            }

            String inputPassword = ShiroKit.md5(passwordDTO.getOldPwd(), user.getSalt());
            if (!inputPassword.equals(user.getPassword())) {
                throw new BusinessException(BizExceptionEnum.OLD_PWD_NOT_RIGHT);
            }

            if (!passwordDTO.getNewPwd().equals(passwordDTO.getRePwd())) {
                throw new BusinessException(BizExceptionEnum.TWO_PWD_NOT_MATCH);
            }
            user.setPassword(ShiroKit.md5(passwordDTO.getNewPwd(), user.getSalt()));

            user.setUpdateTime(LocalDateTime.now());
            user.updateById();
            deleteLoginRedis(sysType,user.getAccount());
        }


    }

    /**
     * 注册用户
     * @param registerDTO
     * @return
     */
    @Transactional
    @Override
    public UserLoginResponse register(RegisterDTO registerDTO) {
        String account=registerDTO.getPhone();
        String newPwd=registerDTO.getNewPwd();
        String rePwd=registerDTO.getRePwd();
        Integer sysType=registerDTO.getSysType();

        if(!account.matches(RegUtils.MOBILE_PHONE)){
            throw new BusinessException(BizExceptionEnum.PHONE_FORMAT_ERROR);
        }
        if(!newPwd.equals(rePwd)){
            throw new BusinessException(BizExceptionEnum.TWO_PWD_NOT_MATCH);
        }
        if(sysType!=PlatformEnum.USER.getCode()&&sysType!=PlatformEnum.COMPANY.getCode()){
            throw new BusinessException(BizExceptionEnum.SYSTYPE_PRAM_ERRO);
        }
        User user = checkUserAccount(account,sysType);
        if (user!=null) {
            throw new BusinessException(BizExceptionEnum.ACCOUNT_EXIST);
        }

        User newUser=new User();
        newUser.setAccount(account);
        newUser.setSysType(sysType);
        String salt=JwtTokenUtil.getRandomKey();
        newUser.setSalt(salt);
        String inputPassword = ShiroKit.md5(newPwd, salt);
        newUser.setPassword(inputPassword);
        newUser.setStatus(UserStatusEnum.NORMAL.getType());
        userMapper.insert(newUser);
        if(sysType==PlatformEnum.COMPANY.getCode()){
            Company   company = companyService.createCompany();
            newUser.setCompanyId(company.getId());
            newUser.setUpdateTime(LocalDateTime.now());
            userMapper.updateById(newUser);
        }else {
            Long userDetailId=userDetailService.createUserDetail();
            newUser.setCompanyId(userDetailId);
            newUser.setUpdateTime(LocalDateTime.now());
            userMapper.updateById(newUser);
        }
        //token-areaid登录接口
        String userAccount = account;
        String token = JwtTokenUtil.generateToken(sysType+":"+newUser.getId() + ":" + userAccount);
        logger.info("-------------------------------------register ip：{}，  login token：{}", HttpKit.getIp(), token);
        UserLoginResponse userLoginResponse=new UserLoginResponse();
        userLoginResponse.setName(newUser.getName());
        userLoginResponse.setToken(token);

        addLoginRedis(sysType,account,token);
        return userLoginResponse;
    }

    /**
     * 修改手机号码
     * @param modifyPhoneDTO
     * @param userId
     */
    @Transactional
    @Override
    public void changPhone(ModifyPhoneDTO modifyPhoneDTO, Long userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(BizExceptionEnum.ACCOUNT_NOT_EXIST);
        }
        if (user.getStatus().equals(UserStatusEnum.FROZEN.getType())) {
            throw new BusinessException(BizExceptionEnum.ACCOUNT_DISABLE);
        }
        if (!user.getSysType().equals(PlatformEnum.COMPANY.getCode())) {
            throw new BusinessException(BizExceptionEnum.NOT_COMPANY);
        }
        if(user.getAccount().equals(modifyPhoneDTO.getPhone())){
            throw new BusinessException(BizExceptionEnum.ACCOUNT_IS_SAME_EXIST);
        }
        deleteLoginRedis(user.getSysType(),user.getAccount());
        user.setAccount(modifyPhoneDTO.getPhone());
        user.setUpdateTime(LocalDateTime.now());
        user.updateById();
    }

    /**
     * 获取平台用户数据
     *
     * @param userId
     * @return
     */
    @Override
    public PlatformUserDetialDTO getPlatformUser(Long userId) {
        PlatformUser platformUser = platformUserMapper.selectById(userId);
        if (platformUser == null) {
            throw new BusinessException(BizExceptionEnum.ACCOUNT_NOT_EXIST);
        }
        PlatformUserDetialDTO platformUserDetialDTO = new PlatformUserDetialDTO();
        platformUserDetialDTO.setAccount(platformUser.getAccount());
        platformUserDetialDTO.setName(platformUser.getName());
        return platformUserDetialDTO;
    }

    /**
     * 修改平台用户名称
     * @param userId
     * @param name
     * @return
     */
    @Override
    public Long updateUserName(Long userId, String name) {
        PlatformUser platformUser = platformUserMapper.selectById(userId);
        if (platformUser == null) {
            throw new BusinessException(BizExceptionEnum.ACCOUNT_NOT_EXIST);
        }
        if(platformUser.getName().equals(name)){
            return platformUser.getId();
        }
        platformUser.setName(name);
        platformUser.setUpdateTime(LocalDateTime.now());
        platformUser.setUpdateUser(userId);
        platformUserMapper.updateById(platformUser);
        return platformUser.getId();
    }

    /**
     * 重置用户密码
     * @param resetPasswordDTO
     * @param userId
     * @return
     */
    @Override
    public Long resetPwd(ResetPasswordDTO resetPasswordDTO, Long userId) {
        User user = userMapper.selectById(resetPasswordDTO.getId());
        if (user == null) {
            throw new BusinessException(BizExceptionEnum.ACCOUNT_NOT_EXIST);
        }
        user.setPassword(ShiroKit.md5(resetPasswordDTO.getPassword(), user.getSalt()));
        deleteLoginRedis(user.getSysType(),user.getAccount());
        user.setUpdateTime(LocalDateTime.now());
        user.setUpdateUser(userId);
        user.updateById();
        return user.getId();
    }

    /**
     * 退出登录
     * @param sysType
     * @param account
     */
    private void deleteLoginRedis(Integer sysType,String account){
        String redisKey= JwtConstants.SCENICBOOT +String.valueOf(sysType)+":"+account;
        String ip = IPUtils.getIPAddress(HttpServletUtils.getRequest());
        if (sysType.equals(PlatformEnum.PLATFORM.getCode())) {
            redisKey = JwtConstants.SCENICBOOT + ip + ":" + account;
        }
        redisUtil.del(redisKey);
    }
    /**
     * 登录
     * @param sysType
     * @param account
     */
    private String addLoginRedis(Integer sysType,String account,String token){
        String ip = IPUtils.getIPAddress(HttpServletUtils.getRequest());
        String redisKey= JwtConstants.SCENICBOOT +String.valueOf(sysType)+":"+account;
        if (sysType.equals(PlatformEnum.PLATFORM.getCode())) {
            redisKey = JwtConstants.SCENICBOOT + ip + ":" + account;
            String tempToken=String.valueOf(redisUtil.get(redisKey));
            if(!"null".equals(tempToken)&&!StringUtils.isEmpty(tempToken)){
                redisUtil.expire(redisKey, JwtConstants.EXPIRE_TIME[1]);
                return tempToken;
            }
        }
        redisUtil.set(redisKey, token);
        redisUtil.expire(redisKey, JwtConstants.EXPIRE_TIME[1]);
        logger.info("-------------------------------------login ip：{},redisKey:{},  login token：{}", HttpKit.getIp(),redisKey,token);
        return token;
    }
}
